package com.xlh.virtualization.websocket;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.xlh.service.course.ChapterExtendService;
import com.xlh.util.SpringContextUtil;
import com.xlh.virtualization.domain.ContainerContext;
import com.xlh.virtualization.job.delayed.RedirectToTheoryListener;
import com.xlh.virtualization.job.delayed.RedirectToTheoryTask;
import com.xlh.virtualization.job.delayed.StopContainerListener;
import com.xlh.virtualization.job.delayed.StopContainerTask;
import com.xlh.virtualization.websocket.message.NoticeStopMessage;
import com.xlh.websocket.GetHttpSessionConfigurator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

import static com.xlh.virtualization.constant.ContextTypeEnum.COURSE;
import static com.xlh.virtualization.constant.ContextTypeEnum.TASK;

/**
 * 实验跳转到理论课的websocket
 *
 * @author cheer
 */
@ServerEndpoint(value = "/ws/theory/{chapterId}", configurator = GetHttpSessionConfigurator.class)
@Component
@Slf4j
public class RedirectToTheoryWebsocket {

    private static final ChapterExtendService chapterExtendService = SpringContextUtil.getBean(ChapterExtendService.class);

    /**
     * 存储连接
     */
    private static Multimap<ContainerContext, RedirectToTheoryWebsocket> connectionMap = HashMultimap.create();

    private Session session;

    private ContainerContext containerContext;

    @OnOpen
    public void onOpen(Session session, @PathParam("chapterId") Long chapterId, EndpointConfig config) {
        this.session = session;
        Long userId = (Long) config.getUserProperties().get("userId");

        Map<String, Object> map = chapterExtendService.getCourseInfo(chapterId);
        if (map == null || map.get("courseImageLoaded") == null) {
            log.error("任务id没有对应的课程信息");
            return;
        }

        if ((boolean) map.get("courseImageLoaded")) {
            this.containerContext = new ContainerContext()
                    .setUserId(userId)
                    .setContextType(COURSE.getCode())
                    .setContextId((Long) map.get("courseId"));
        } else {
            this.containerContext = new ContainerContext()
                    .setUserId(userId)
                    .setContextType(TASK.getCode())
                    .setContextId(chapterId);
        }

        synchronized (RedirectToTheoryWebsocket.class) {
            connectionMap.put(containerContext, this);
            RedirectToTheoryTask task = new RedirectToTheoryTask(containerContext, RedirectToTheoryTask.TaskTypeEnum.NOTICE);
            RedirectToTheoryListener.putTask(task);
        }
    }

    @OnClose
    public void onClose() {
        synchronized (RedirectToTheoryWebsocket.class) {
            connectionMap.remove(containerContext, this);

            if (!connectionMap.containsKey(containerContext)) {
                StopContainerTask task = new StopContainerTask(containerContext);
                StopContainerListener.putTask(task);
            }
        }
    }

    @OnMessage
    public void onMessage(String jsonStr, Session session) {
        // 暂时不需要实现该方法
    }

    @OnError
    public void onError(Session session, Throwable error) {
        // 暂时不需要实现该方法
    }

    /**
     * 提示用户容器即将停止
     */
    public static void notifyStopContainer(ContainerContext containerContext) {
        Collection<RedirectToTheoryWebsocket> websocketList = connectionMap.get(containerContext);
        if (CollectionUtils.isNotEmpty(websocketList)) {
            NoticeStopMessage noticeStopMessage = NoticeStopMessage.builder().build();
            String message = JSONObject.toJSONString(noticeStopMessage);
            for (RedirectToTheoryWebsocket websocket : websocketList) {
                try {
                    websocket.session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.warn("websocket send message exception", e);
                }
            }
        }
    }

    public static Boolean isOnline(ContainerContext containerContext) {
        return connectionMap.containsKey(containerContext);
    }
}
